#include "defines.h"
#include "timer.h"
#include "lib.h"

#define REGADDR 0x200000
#define CR      ((volatile uint8 *) REGADDR + 0x00)
#define RDMAP   ((volatile uint8 *) REGADDR + 0x10)
#define RP      ((volatile uint8 *) REGADDR + 0x18)

// Page 1
#define PSTART  ((volatile uint8 *) REGADDR + 0x01)
#define PSTOP   ((volatile uint8 *) REGADDR + 0x02)
#define BNRY    ((volatile uint8 *) REGADDR + 0x03)
#define TPSR    ((volatile uint8 *) REGADDR + 0x04)
#define TBCR0   ((volatile uint8 *) REGADDR + 0x05)
#define TBCR1   ((volatile uint8 *) REGADDR + 0x06)
#define ISR     ((volatile uint8 *) REGADDR + 0x07)
#define RSAR0   ((volatile uint8 *) REGADDR + 0x08)
#define RSAR1   ((volatile uint8 *) REGADDR + 0x09)
#define RBCR0   ((volatile uint8 *) REGADDR + 0x0a)
#define RBCR1   ((volatile uint8 *) REGADDR + 0x0b)
#define RCR     ((volatile uint8 *) REGADDR + 0x0c)
#define TCR     ((volatile uint8 *) REGADDR + 0x0d)
#define DCR     ((volatile uint8 *) REGADDR + 0x0e)
#define IMR     ((volatile uint8 *) REGADDR + 0x0f)

// Page 2
#define PAR0    ((volatile uint8 *) REGADDR + 0x01)
#define PAR1    ((volatile uint8 *) REGADDR + 0x02)
#define PAR2    ((volatile uint8 *) REGADDR + 0x03)
#define PAR3    ((volatile uint8 *) REGADDR + 0x04)
#define PAR4    ((volatile uint8 *) REGADDR + 0x05)
#define PAR5    ((volatile uint8 *) REGADDR + 0x06)
#define CURR    ((volatile uint8 *) REGADDR + 0x07)
#define MAR0    ((volatile uint8 *) REGADDR + 0x08)
#define MAR1    ((volatile uint8 *) REGADDR + 0x09)
#define MAR2    ((volatile uint8 *) REGADDR + 0x0a)
#define MAR3    ((volatile uint8 *) REGADDR + 0x0b)
#define MAR4    ((volatile uint8 *) REGADDR + 0x0c)
#define MAR5    ((volatile uint8 *) REGADDR + 0x0d)
#define MAR6    ((volatile uint8 *) REGADDR + 0x0e)
#define MAR7    ((volatile uint8 *) REGADDR + 0x0f)

#define TP_START    0x40
#define RP_START    0x46
#define RP_STOP     0x60

#define FRAME_MINSIZE   60
#define FRAME_MAXSIZE   1514

int nic_init(uint8 *MAC)
{
    int i;
    uint8 x;

    x = *RP;
    *RP = x;
    delay_ms(10);

    *CR = 0x21;
    *DCR = 0x4a;
    *RBCR0 = 0;
    *RBCR1 = 0;
    *RCR = 0x20;
    *TCR = 0x02;
    *TPSR = TP_START;
    *PSTART = RP_START;
    *BNRY = RP_START;
    *PSTOP = RP_STOP;
    *IMR = 0;
    *ISR = 0xff;

    // MACの読み込み。
    *RBCR0 = 12;
    *RBCR1 = 0;
    *RSAR0 = 0;
    *RSAR1 = 0;
    *CR = 0x0a;
    for (i = 0; i < 6; i++) {
        MAC[i] = *RDMAP;
        x = *RDMAP;
    }

    *CR = 0x61;
    *PAR0 = MAC[0];
    *PAR1 = MAC[1];
    *PAR2 = MAC[2];
    *PAR3 = MAC[3];
    *PAR4 = MAC[4];
    *PAR5 = MAC[5];

    *CURR = RP_START + 1;

    *MAR0 = 0;
    *MAR1 = 0;
    *MAR2 = 0;
    *MAR3 = 0;
    *MAR4 = 0;
    *MAR5 = 0;
    *MAR6 = 0;
    *MAR7 = 0;

    *CR = 0x21;
    *RCR = 0x04;
    *CR = 0x22;
    *TCR = 0;
    *IMR = 0;

    return 0;
}

static void wait_send()
{
    while (*CR & 0x04)
        ;
}

static void check_overflow()
{
    *CR = 0x22;
    if (*ISR & 0x10) {
        wait_send();
        *CR = 0x21;
        delay_ms(2);
        *RBCR0 = 0;
        *RBCR1 = 0;
        *TCR = 0x02;
        *BNRY = RP_START;
        *CR = 0x61;
        *CURR = RP_START + 1;
        *CR = 0x21;
        *ISR = 0x10;
        *CR = 0x22;
        *TCR = 0;
    }
}

int frame_send(uint8 *buffer, uint16 size)
{
    uint16 i;
    uint8 size_h, size_l;

    if (size > FRAME_MAXSIZE) return -1;

    check_overflow(); // 返事を受信できないとロスなので

    wait_send();

    size_l = (uint8)size;
    size_h = (uint8)(size >> 8);

    // バッファへ転送
    *CR = 0x22;
    *RBCR0 = size_l;
    *RBCR1 = size_h;
    *RSAR0 = 0;
    *RSAR1 = TP_START;
    *ISR = 0x40;
    *CR = 0x12;
    for (i = 0; i < size; i++) {
        *RDMAP = buffer[i];
    }
    while (!(*ISR & 0x40))
        ;

    // 実際の送信
    *CR = 0x22;
    *TBCR0 = (size > FRAME_MINSIZE) ? size_l : FRAME_MINSIZE;
    *TBCR1 = size_h;
    *TPSR = TP_START;
    *CR = 0x26;

    return 0;
}

int frame_receive(uint8 *buffer) // バッファは1514バイト書き込めるとする
{
    uint16 i, size;
    uint8 x, start;
    uint8 header[4];
    int ret = 0;

    check_overflow();

    *CR = 0x22;
    x = *BNRY;
    start = (x == RP_STOP - 1) ? RP_START : x + 1;

    *CR = 0x62;
    if (*CURR == start) { // 受信してない
        return 1;
    }

    *CR = 0x22;
    *RBCR0 = 4;
    *RBCR1 = 0;
    *RSAR0 = 0;
    *RSAR1 = start;
    *CR = 0x0a;
    for (i = 0; i < 4; i++) {
        header[i] = *RDMAP;
    }

    if (!(header[0] & 0x01)) { // 異常受信
        ret = -1;
        goto refresh_bnry;
    }

    size = ((uint16)header[3] << 8) + header[2] - 4;
    if (size > FRAME_MAXSIZE) {
        ret = -1;
        goto refresh_bnry;
    }

    *CR = 0x22;
    *RBCR0 = (uint8)size;
    *RBCR1 = (uint8)(size >> 8);
    *RSAR0 = 4;
    *RSAR1 = start;
    *CR = 0x0a;
    for (i = 0; i < size; i++) {
        buffer[i] = *RDMAP;
    }

refresh_bnry:
    *CR = 0x22;
    *BNRY = (header[1] == RP_START) ? RP_STOP - 1 : header[1] - 1;

    return ret;
}
